# 自动下载小鹅通的课程视频
import requests
from DrissionPage import ChromiumPage
import os
import execjs
import time
from urllib.parse import urlparse
from Crypto.Cipher import AES
from urllib.request import urlopen

class Xiaoetong:
    def __init__(self, url):
        self.page = ChromiumPage(addr_or_opts='127.0.0.1:9333')
        self.url = url

    def get_courses(self):
        self.page.listen.start(targets='xe.course.business.column.items.get/2.0.0', is_regex=True)
        self.page.get(self.url)
        course_json = {}
        for packet in self.page.listen.steps():
            if 'xe.course.business.column.items.get/2.0.0' in packet.url:
                course_json = packet.response.body
                break
        list = course_json['data']['list']
        print(list)
        courses = []
        for item in list:
            jump_url = self.url.split('/p/course')[0] + item['jump_url']
            resource_title = item['resource_title']
            courses.append({'jump_url': jump_url, 'resource_title': resource_title})
        return courses
    def download_video(self, course):
        current_directory = os.path.dirname(os.path.abspath(__file__))
        os.chdir(current_directory)
        if os.path.exists('%s.mp4' % course['resource_title']):
            print(f"{course['resource_title']}已存在")
            return
        self.page.listen.start(targets=['.m3u8*','sign='], is_regex=True)
        self.page.get(course['jump_url'])
        m3u8_url = ''
        flag1 = False
        flag2 = False
        ts_url_params = {}
        for packet in self.page.listen.steps():
            if '.m3u8' in packet.url:
                m3u8_url = packet.url
                flag1 = True
            if 'sign=' in packet.url and 't=' in packet.url and 'us=' in packet.url:
                t_u_p = packet.url.split('sign=')[0]
                parsed_url = urlparse(t_u_p)
                pre_url = parsed_url.scheme + "://" + parsed_url.netloc + "/".join(parsed_url.path.split("/")[:-1])
                ts_url_params = {"sign": packet.url.split('sign=')[1].split('&')[0], "t": packet.url.split('t=')[1].split('&')[0], "us": packet.url.split('us=')[1], "pre_url": pre_url}
                flag2 = True
            if flag1 and flag2:
                break
        m3u8 = requests.request("GET", m3u8_url).text
        # 如果以[xiaoe]开头，则使用xet.js解密
        if m3u8.startswith('[xiaoe]'):
            f = open('xet.js', encoding='utf-8').read()
            js_code = execjs.compile(f)
            m3u8 = js_code.call('N', m3u8)
        with open('%s.m3u8' % course['resource_title'], 'w', encoding='utf-8') as f:
            f.write(m3u8)
        ts_list = m3u8.split('\n')
        ts_is_encrypted = False
        for ts in ts_list:
            # 判断 ts 文件是否加密
            if ts.startswith('#EXT-X-KEY'):
                ts_is_encrypted = True
                key_url= ts.split('URI="')[1].split('"')[0]
            if ts.startswith('#'):
                ts_list.remove(ts)

        # 执行下载
        for ts in ts_list:
            if '.ts?' in ts:
                if 'sign' in ts:
                    ts_url = "%s/%s" % (ts_url_params['pre_url'],ts)
                else:
                    ts_url = "%s/%s&sign=%s&t=%s&us=%s" % (ts_url_params['pre_url'],ts,ts_url_params['sign'],ts_url_params['t'],ts_url_params['us'])
                try:
                    self.page.download(ts_url, 'ts/%s' % course['resource_title'])
                except Exception as e:
                    print(e)
                    print(f"{ts_url}下载失败")
                    break
                
        cmd = 'cat '
        
        i = 0
        for ts in ts_list:
            if '.ts?' in ts:
                if 'start' in ts:
                    if i == 0:
                        cmd += '"ts/%s/' % course['resource_title'] + ts.split('?')[0] + '" '
                    else:
                        cmd += '"ts/%s/' % course['resource_title'] + ts.split('.ts')[0] + '_' + str(i) + '.ts" '
                    i += 1
                else:
                    cmd += '"ts/%s/' % course['resource_title'] + ts.split('?')[0] + '" '
        cmd += '> "%s.ts"' % course['resource_title']
        with open('cmd.txt', 'w', encoding='utf-8') as f:
            f.write(cmd)
        os.system(cmd)
        if ts_is_encrypted:
            key = urlopen(key_url).read()
            # 获取加密的TS文件
            with open('%s.ts' % course['resource_title'], 'rb') as f:
                encrypted_ts = f.read()
            # 创建一个新的AES对象
            cipher = AES.new(key, AES.MODE_CBC, IV=b'\x00'*16)

            # 解密TS文件
            decrypted_ts = cipher.decrypt(encrypted_ts)

            # 写入新的TS文件
            with open('decrypted.ts', 'wb') as f:
                f.write(decrypted_ts)
            # 重命名
            os.rename('decrypted.ts', '%s.ts' % course['resource_title'])
        os.system('ffmpeg -i "%s.ts" -acodec copy -vcodec copy "%s.mp4"' % (course['resource_title'], course['resource_title']))
        os.system('ffmpeg -i "%s.mp4" -vn -acodec copy "%s.aac"' % (course['resource_title'], course['resource_title']))
        return True


if __name__ == '__main__':
    url = 'https://app8aplieli4282.h5.xiaoeknow.com/p/course/column/p_64d0bca5e4b0b0bc2c089903'
    x = Xiaoetong(url)
    courses = x.get_courses()
    print(courses)
    for course in courses:
        x.download_video(course)
        time.sleep(5)
    print('下载完成')
